// Promise 有三种状态：pending、fulfilled,rejected
const PENDING = 'pending'
const FULFILLDED = 'fulfilled'
const REJECTED = 'rejected'

// Promise是个类
class MyPromise {
  constructor(executor) {
    try {
      executor(this.resolve, this.reject)
    } catch (error) {
      this.reject(error)
    }
  }

  // promise初始化状态
  status = PENDING
  // 成功后的值
  value = undefined
  // 失败的原因
  reason = undefined
  // 成功回调
  successCallback = []
  // 失败回调
  failCallback = []

  changeStatus(status, value) {
    // 如果状态不是pending，则直接返回
    if (this.status !== PENDING) return
    // 将状态变更为成功或者失败
    this.status = status
    // 保存成功或者失败的值
    this.value = value
    // 如果状态成功
    if (status === FULFILLDED) {
      while (this.successCallback.length) this.successCallback.shift()()
    } else {
      while (this.failCallback.length) this.failCallback.shift()()
    }
  }

  resolve = value => {
    this.changeStatus(FULFILLDED, value)
  }
  reject = reason => {
    this.changeStatus(REJECTED, reason)
  }
  then(successCallback, failCallback) {
    successCallback = successCallback ? successCallback : value => value
    failCallback = failCallback ? failCallback : reason => {
      throw reason
    }
    let newPromise = new MyPromise((resolve, reject) => {
      // 判断状态
      if (this.status === FULFILLDED) {
        // 通过设置setTimeout将下面代码变成异步代码达到避免获取不到newPromise对象问题
        setTimeout(() => {
          try {
            const x = successCallback(this.value)
            // 判断 x 的值是普通值还是Promise对象
            // 如果是普通值 直接调用resolve
            // 如果是Promise对象 查看Promise对象返回的结果
            // 再根据Promise对象返回的结果 决定调用resolve 还是调用reject
            promiseThen(newPromise, x, resolve, reject)
          } catch (error) {
            reject(error)
          }
        }, 0)
      } else if (this.status === REJECTED) {
        // 通过设置setTimeout将下面代码变成异步代码达到避免获取不到newPromise对象问题
        setTimeout(() => {
          try {
            const x = failCallback(this.reason)
            // 判断 x 的值是普通值还是Promise对象
            // 如果是普通值 直接调用resolve
            // 如果是Promise对象 查看Promise对象返回的结果
            // 再根据Promise对象返回的结果 决定调用resolve 还是调用reject
            promiseThen(newPromise, x, resolve, reject)
          } catch (error) {
            reject(error)
          }
        }, 0)
      } else {
        // 状态为pending
        // 将成功回调和失败回调都存储起来
        this.successCallback.push(() => {
          setTimeout(() => {
            try {
              const x = successCallback(this.value)
              // 判断 x 的值是普通值还是Promise对象
              // 如果是普通值 直接调用resolve
              // 如果是Promise对象 查看Promise对象返回的结果
              // 再根据Promise对象返回的结果 决定调用resolve 还是调用reject
              promiseThen(newPromise, x, resolve, reject)
            } catch (error) {
              reject(error)
            }
          }, 0)
        })
        this.failCallback.push(() => {
          setTimeout(() => {
            try {
              const x = failCallback(this.reason)
              // 判断 x 的值是普通值还是Promise对象
              // 如果是普通值 直接调用resolve
              // 如果是Promise对象 查看Promise对象返回的结果
              // 再根据Promise对象返回的结果 决定调用resolve 还是调用reject
              promiseThen(newPromise, x, resolve, reject)
            } catch (error) {
              reject(error)
            }
          }, 0);
        })
      }
    })
    // 返回Promise对象
    return newPromise
  }
  finally(callback) {
    return this.then(value => {
      return MyPromise.resolve(callback()).then(() => value)
    })
  }
  //
  catch (callback) {
    return this.then(undefined, callback)
  }
  static all(array) {
    return new MyPromise((resolve, reject) => {
      let result = []
      let count = 0

      function addData(index, value) {
        result[key] = value
        count++
        if (count === array.length) {
          resolve(result)
        }
      }
      array.forEach((item, index) => {
        if (item instanceof MyPromise) {
          // Promise对象
          item.then(value => addData(index, value), reason => reject(reason))
        } else {
          // 普通值
          addData(index, item)
        }
      });
    })
  }
  static resolve(value) {
    if (value instanceof MyPromise) return value
    return new MyPromise(resolve => resolve(value))
  }
  static reject(reason) {
    if (reason instanceof MyPromise) return reason
    return new MyPromise((_, reject) => reject(reason))
  }
}

function promiseThen(promise, x, resolve, reject) {
  if (promise === x) {
    // 拒绝自我调用
    reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
  }
  if (x instanceof MyPromise) {
    x.then(value => resolve(value), reason => reject(reason))
  } else {
    // 普通值
    resolve(x)
  }
}

module.exports = MyPromise